// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`include "mainfpga_version.vh"

module cpu_aux
  (
   input           iClk,
   input           iRst_n,
   input           iFM_INTR_PRSNT_N,
   input           iINTR_PRSNT_N,
   input           iCPU_AUX_EN,                                        // From master_fub, enable CPU AUX power domain
   input           iPWRGD_P1V0_AUX,                                    // used here when there is no interposer
   input           iPWRGD_PVCCFA_EHV_CPU,                              // From VCCFA_EHV VR, indicate this VR is fully on
   input           iPWRGD_PVNN_MAIN_CPU,                               // From VNN_MAIN VR, indicate this VR is fully on
   input           iclear_error_state,                                 // From master_fub, indicate BMC force to exit error state
   input           iPWRGD_P3V3_AUX,                                    // From baseboard 3V3_AUX VR, indicate this VR is fully on (for T3 timing requirement)
   input           iPWRGD_PVNN_MAIN_CPU0,                              // From CPU0 VNN_MAIN VR, indicate this VR is fully on (for T4 timing requirement)
   input		   iPWRGD_P1V2_MAX10_AUX_PLD_R_LVC3,
   input           iIsLegacy,                                          // To distinguish between CPU Legacy and No-Legacy
   
   output reg      oCPU_AUX_PWRGD,                                     // To master_fub, indicate all VRs of CPU AUX domain are on
   output reg      oCPU_AUX_PWR_FLT,                                   // To master_fub, indicate CPU AUX VR failure
   output reg      oPWROFF_TIMEOUT_ERR,                                // To master_fub, indicate timeout error during certain VR power off
   output reg      oCPU_PWR_FLT_EHV,                                   // To debug FPGA through sGPIO, indicate error source is VCCFA_EHV VR
   output reg      oCPU_PWR_FLT_PVNN_MAIN,                             // To debug FPGA through sGPIO, indicate error source is VNN_MAIN VR
   output reg      oFM_PVCCFA_EHV_CPU_EN,                              // To VCCFA_EHV VR, enable this VR
   output reg      oFM_P1V0_AUX_EN,                                    // used here when there is no interposer
   output reg      oFM_PVNN_MAIN_CPU_EN                                // To VNN_MAIN VR, enable this VR
   );
   
   /*************************************************************************************************************
    * Local Parameter Definitions                                                                               *
    *************************************************************************************************************/
   localparam  LOW  = 1'b0;
   localparam  HIGH = 1'b1;
   
`ifdef SIMULATION
   localparam  T_1mS_2M    = 11'd1000;
   localparam  T_50mS_2M   = 11'd1000;
   localparam  T_100mS_2M  = 11'd1000;
`else
   localparam  T_1mS_2M    = 12'd2000;
   localparam  T_50mS_2M   = 18'd100000;
   localparam  T_100mS_2M  = 19'd200000;
`endif
   
   localparam  ST_INIT             = 3'd0;
   localparam  ST_PVCCFA_EHV       = 3'd1;
   localparam  ST_PVNN_MAIN        = 3'd2;
   localparam  ST_CPU_AUX_ON       = 3'd3;
   localparam  ST_PVCCFA_EHV_OFF   = 3'd4;
   localparam  ST_PVNN_MAIN_OFF    = 3'd5;
   localparam  ST_PWROFF_TIMEOUT   = 3'd6;
   
   /*************************************************************************************************************
    * Local Registers and Wires Definitions                                                                     *
    *************************************************************************************************************/
   reg [2:0]       rstate;
   reg             rStart100msTimer;
   reg             rPWRGD_PVCCFA_EHV_CPU;
   reg             rPWRGD_PVNN_MAIN_CPU;
   
   wire            wStart100msTimer;       // For VR power off timeout: max 100 ms delay
   wire            wDoneTimer100ms;
   wire            wDoneTimer_T3;          // For T3: min 50 ms delay
   wire            wDoneTimer_T4;          // For T4: min 1 ms delay
   
   /*************************************************************************************************************
    * Logic                                                                                                     *
    *************************************************************************************************************/
   assign wStart100msTimer = rStart100msTimer;
   
   always @ (posedge iClk or negedge iRst_n) begin                     // CPU AUX VRs Control Logic
      if (!iRst_n) begin
         oCPU_AUX_PWRGD                  <= LOW;
         oFM_PVCCFA_EHV_CPU_EN           <= LOW;
         oFM_PVNN_MAIN_CPU_EN            <= LOW;
         oFM_P1V0_AUX_EN                 <= LOW;
         oPWROFF_TIMEOUT_ERR             <= LOW;
         rStart100msTimer                <= LOW;
         
         rstate                          <= ST_INIT;
      end
      else begin
         if (iFM_INTR_PRSNT_N)        //interposer is not present
           begin
              case (rstate)
                ST_INIT: begin                                          // Initial state
                   oCPU_AUX_PWRGD          <= LOW;
                   oFM_PVCCFA_EHV_CPU_EN   <= LOW;
                   oFM_PVNN_MAIN_CPU_EN    <= LOW;
                   
				   
				   if(iPWRGD_P1V2_MAX10_AUX_PLD_R_LVC3) begin
				     oFM_P1V0_AUX_EN         <= HIGH;
				   end
				   
                   if (iFM_INTR_PRSNT_N && iCPU_AUX_EN && wDoneTimer_T3 && !oCPU_AUX_PWR_FLT) begin    // master_fub ask to turn on CPU AUX power domain, T3 done, and no pwr failure status
                      rstate              <= ST_PVCCFA_EHV;
                   end
                end // case: ST_INIT
                
                ST_PVCCFA_EHV: begin                                    // Turn on VCCFA_EHV VR for S3M, PCIe gen5, UPI IO and other FIVR domain support
                   oFM_PVCCFA_EHV_CPU_EN   <= HIGH;
                   if (!iCPU_AUX_EN || oCPU_AUX_PWR_FLT) begin         // Power off or power failure, turn off CPU AUX VRs
                      oCPU_AUX_PWRGD      <= LOW;
                      rstate              <= ST_PVNN_MAIN_OFF;
                   end else if (iPWRGD_PVCCFA_EHV_CPU) begin                // VCCFA_EHV VR already turned on, go to next stage
                      rstate              <= ST_PVNN_MAIN;
                   end
                end // case: ST_PVCCFA_EHV
                
                ST_PVNN_MAIN: begin                                     // Turn on VNN_MAIN VR for S3M and other on package CPLD support
                   oFM_PVNN_MAIN_CPU_EN    <= HIGH;
                   if (!iCPU_AUX_EN || oCPU_AUX_PWR_FLT) begin         // Power off or power failure, turn off CPU AUX VRs
                      oCPU_AUX_PWRGD      <= LOW;
                      rstate              <= ST_PVNN_MAIN_OFF;
                   end else if (iPWRGD_PVNN_MAIN_CPU && wDoneTimer_T4 && (iPWRGD_P1V0_AUX || !iIsLegacy)) begin// VNN_MAIN VR already turned on and T4 done, all CPU AUX VRs turned on
                      rstate              <= ST_CPU_AUX_ON;
                   end
                end // case: ST_PVNN_MAIN
                
                ST_CPU_AUX_ON: begin                                    // Indicate CPU AUX power domain is on
                   oCPU_AUX_PWRGD          <= HIGH;
                   if (!iCPU_AUX_EN || oCPU_AUX_PWR_FLT) begin         // Power off or power failure, turn off CPU AUX VRs
                      rstate              <= ST_PVNN_MAIN_OFF;
                   end
                end // case: ST_CPU_AUX_ON
                
                ST_PVNN_MAIN_OFF: begin                                 // Turn off VNN_MAIN VR
                   oFM_PVNN_MAIN_CPU_EN    <= LOW;
                   rStart100msTimer        <= HIGH;                    // Start 100 ms watchdog
                   if (iPWRGD_PVNN_MAIN_CPU && wDoneTimer100ms) begin  // Timeout when turning off PVNN_MAIN VR
                      rstate              <= ST_PWROFF_TIMEOUT;
                   end else if (!iPWRGD_PVNN_MAIN_CPU) begin           // VNN_MAIN VR already turned off, go to next stage
                      rStart100msTimer    <= LOW;                     // Clear watchdog
                      rstate              <= ST_PVCCFA_EHV_OFF;
                   end
                end // case: ST_PVNN_MAIN_OFF
                
                ST_PVCCFA_EHV_OFF: begin                                // Turn off VCCFA_EHV VR
                   oFM_PVCCFA_EHV_CPU_EN   <= LOW;
                   rStart100msTimer        <= HIGH;                    // Restart 100 ms watchdog
                   if (iPWRGD_PVCCFA_EHV_CPU && wDoneTimer100ms) begin // Timeout when turning off VCCFA_EHV VR
                      rstate              <= ST_PWROFF_TIMEOUT;
                   end else if (!iPWRGD_PVCCFA_EHV_CPU) begin          // All CPU AUX power domain already turned off, go to initial state
                      rStart100msTimer    <= LOW;                     // Clear watchdog
                      rstate              <= ST_INIT;
                   end
                end // case: ST_PVCCFA_EHV_OFF
                
                ST_PWROFF_TIMEOUT: begin                                // Timeout when turning off certain VR
                   oPWROFF_TIMEOUT_ERR     <= HIGH;
                   oCPU_AUX_PWRGD          <= LOW;
                   oFM_PVCCFA_EHV_CPU_EN   <= LOW;
                   oFM_PVNN_MAIN_CPU_EN    <= LOW;
                   oFM_P1V0_AUX_EN         <= LOW;
                   rStart100msTimer        <= LOW;
                   if (iclear_error_state) begin                       // BMC force to exit error state, try to clear VR failure status. Only valid for CPU1 AUX VR
                      rstate              <= ST_INIT;
                      oPWROFF_TIMEOUT_ERR <= LOW;
                   end
                end // case: ST_PWROFF_TIMEOUT
                
                default: begin
                   oCPU_AUX_PWRGD          <= LOW;
                   oFM_PVCCFA_EHV_CPU_EN   <= LOW;
                   oFM_PVNN_MAIN_CPU_EN    <= LOW;
                   oFM_P1V0_AUX_EN         <= LOW;
                   rStart100msTimer        <= LOW;
                   oPWROFF_TIMEOUT_ERR     <= LOW;
                   rStart100msTimer        <= LOW;
                end // case: default
              endcase // case (rstate)
           end // if (iFM_INTR_PRSNT_N)
         else                                       //interposer is present
           begin
              oCPU_AUX_PWRGD              <= iCPU_AUX_EN && wDoneTimer_T3;
              oPWROFF_TIMEOUT_ERR         <= LOW;
              oFM_PVCCFA_EHV_CPU_EN       <= LOW;
              oFM_P1V0_AUX_EN             <= LOW;
              oFM_PVNN_MAIN_CPU_EN        <= LOW;
           end
      end // else: !if(!iRst_n)
   end // always @ (posedge iClk or negedge iRst_n)
   
   always @ (posedge iClk or negedge iRst_n) begin                     // CPU AUX VRs Fault Logic
      if (!iRst_n) begin
         oCPU_PWR_FLT_EHV            <= LOW;
         oCPU_PWR_FLT_PVNN_MAIN      <= LOW;
         oCPU_AUX_PWR_FLT            <= LOW;
      end
      else if (!iFM_INTR_PRSNT_N) begin
         oCPU_PWR_FLT_EHV            <= LOW;
         oCPU_PWR_FLT_PVNN_MAIN      <= LOW;
         oCPU_AUX_PWR_FLT            <= LOW;
      end
      else if (iclear_error_state) begin                               // BMC force to exit error state, try to clear VR failure status
         oCPU_PWR_FLT_EHV            <= LOW;
         oCPU_PWR_FLT_PVNN_MAIN      <= LOW;
         oCPU_AUX_PWR_FLT            <= LOW;
      end else begin                                              // Detect CPU AUX VR failures, VR PWRGD de-asserted but not in power down flow
         rPWRGD_PVCCFA_EHV_CPU       <= iPWRGD_PVCCFA_EHV_CPU;
         rPWRGD_PVNN_MAIN_CPU        <= iPWRGD_PVNN_MAIN_CPU;
         oCPU_PWR_FLT_EHV            <= (oFM_PVCCFA_EHV_CPU_EN && rPWRGD_PVCCFA_EHV_CPU && !iPWRGD_PVCCFA_EHV_CPU) ? HIGH : oCPU_PWR_FLT_EHV;
         oCPU_PWR_FLT_PVNN_MAIN      <= (oFM_PVNN_MAIN_CPU_EN  && rPWRGD_PVNN_MAIN_CPU  && !iPWRGD_PVNN_MAIN_CPU ) ? HIGH : oCPU_PWR_FLT_PVNN_MAIN;
         oCPU_AUX_PWR_FLT            <= (oCPU_PWR_FLT_EHV || oCPU_PWR_FLT_PVNN_MAIN) ? HIGH: oCPU_AUX_PWR_FLT;
      end
   end // always @ (posedge iClk or negedge iRst_n)
   
   
   
   
   /*************************************************************************************************************
    * Instances                                                                                                 *
    *************************************************************************************************************/
   // T3: min 50 ms delay, from PWRGD_P3V3_AUX assertion to legacy CPU VCCFA_EHV assertion
   delay #(.COUNT(T_50mS_2M))
   Timer50ms_T3 (
                 .iClk    ( iClk            ),
                 .iRst    ( iRst_n          ),
                 .iStart  ( iPWRGD_P3V3_AUX ),
                 .iClrCnt ( 1'b0            ),
                 .oDone   ( wDoneTimer_T3   )
                 );
   
   // T4: min 1 ms delay, from legacy CPU PWRGD_PVNN_MAIN assertion to legacy CPU AUX_PWRGD assertion
   delay #(.COUNT(T_1mS_2M))
   Timer1ms_T4 (
                .iClk    ( iClk                  ),
                .iRst    ( iRst_n                ),
                .iStart  ( iPWRGD_PVNN_MAIN_CPU0 ),
                .iClrCnt ( 1'b0                  ),
                .oDone   ( wDoneTimer_T4         )
                );
   
   // T?: max 100 ms watchdog, started when certain VR enable signal de-asserted
   delay #(.COUNT(T_100mS_2M))
   Timer100ms (
               .iClk    ( iClk             ),
               .iRst    ( iRst_n           ),
               .iStart  ( wStart100msTimer ),
               .iClrCnt ( 1'b0             ),
               .oDone   ( wDoneTimer100ms  )
               );
endmodule // cpu_aux

